package cn.lei.netty.herostory.rank;

import cn.lei.netty.herostory.async.AsyncOperationProcessor;
import cn.lei.netty.herostory.async.IAsyncOperation;
import cn.lei.netty.herostory.util.RedisUtil;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Tuple;

import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.function.Function;

/**
 * 排行榜服务
 *
 * @author lei
 */
public final class RankService {
    /**
     * 日志对象
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(RankService.class);
    /**
     * 单例对象
     */
    private static final RankService INSTANCE = new RankService();

    /**
     * 私有化默认构造器
     */
    private RankService() {
    }

    /**
     * 获取单例
     */
    public static RankService getInstance() {
        return INSTANCE;
    }

    /**
     * 获取排行榜
     *
     * @param callBack 回调函数
     * @return
     */
    public void getRank(Function<List<RankItem>, Void> callBack) {
        if (callBack == null) {
            return;
        }
        AsyncOperationProcessor.getInstance().process(new AsyncGetRank() {
            @Override
            public void doFinish() {
                callBack.apply(this.getRankItemList());
            }
        });
    }

    /**
     * 刷新排行榜
     *
     * @param winnerId 赢家Id
     * @param loserId  输家Id
     */
    public void refreshRank(int winnerId, int loserId) {
        if (winnerId <= 0 || loserId <=0){
            return;
        }
        try(Jedis redis = RedisUtil.getJedis()) {

            redis.hincrBy("User_"+winnerId,"Win",1);
            redis.hincrBy("User_"+loserId,"Lose",1);

            String winStr = redis.hget("User_" + winnerId, "Win");
            int winNum = Integer.parseInt(winStr);

            //修改排名
            redis.zadd("Rank",winNum,String.valueOf(winnerId));
        }catch (Exception ex){
            LOGGER.error(ex.getMessage(),ex);
        }
    }

    /**
     * 异步方式获取排行榜
     */
    private class AsyncGetRank implements IAsyncOperation {
        /**
         * 排行榜条目
         */
        private List<RankItem> rankItemList;

        /**
         * 获取排行榜条目
         *
         * @return
         */
        List<RankItem> getRankItemList() {
            return rankItemList;
        }

        @Override
        public void doAsync() {
            try (Jedis redis = RedisUtil.getJedis()) {

                Set<Tuple> valSet = redis.zrangeWithScores("Rank", 0, 9);

                List<RankItem> rankItemList = new LinkedList<>();
                int i = 0;

                for (Tuple t : valSet) {
                    if (t == null) {
                        continue;
                    }

                    //userId
                    int userId = Integer.parseInt(t.getElement());

                    //获取用户信息
                    String jsonStr = redis.hget("User_" + userId, "BasicInfo");

                    if (jsonStr == null) {
                        continue;
                    }

                    //构建排名条目
                    RankItem newItem = new RankItem();
                    newItem.rankId = ++i;
                    newItem.userId = userId;
                    newItem.win = (int) t.getScore();

                    JSONObject jsonObj = JSONObject.parseObject(jsonStr);
                    newItem.userName = jsonObj.getString("userName");
                    newItem.heroAvatar = jsonObj.getString("heroAvatar");

                    rankItemList.add(newItem);
                }
                this.rankItemList = rankItemList;
            } catch (Exception ex) {
                LOGGER.error(ex.getMessage(), ex);
            }
        }
    }

}
